/*!
 Temelia - samples common interface implementation.

 Copyright (C) 2008 Ceata (http://ceata.org/proiecte/temelia).

 @author Dascalu Laurentiu

 This program is free software; you can redistribute it and
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 3
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "include/samples.h"

static char
		test_names[][MAX_TEST_LENGTH] =
		{ "algorithms", "avl_tree", "b_tree", "binary_search_tree",
				"binary_tree", "doubly_linked_list", "hash_set", "hash_map",
				"heap", "interval_tree", "linked_list", "matrix", "graph",
				"graph_matrix", "graph_sparse_matrix", "graph_list", "pair",
				"queue", "red_black_tree", "sparse_matrix", "scapegoat_tree",
				"skip_list", "sort", "splay_tree", "stack", "treap_tree",
				"tree_algorithms", "tree", "trie_tree", "vector" };

static void (*test_pointers[])() =
{ run_algorithms_samples, run_avl_tree_samples, run_b_tree_samples,
		run_binary_search_tree_samples, run_binary_tree_samples,
		run_doubly_linked_list_samples, run_hash_set_samples,
		run_hash_map_samples, run_heap_samples, run_interval_tree_samples,
		run_linked_list_samples, run_matrix_samples, run_graph_samples,
		run_graph_matrix_samples, run_graph_sparse_matrix_samples,
		run_graph_list_samples, run_pair_samples, run_queue_samples,
		run_red_black_tree_samples, run_sparse_matrix_samples,
		run_scapegoat_tree_samples, run_skip_list_samples, run_sort_samples,
		run_splay_tree_samples, run_stack_samples, run_treap_tree_samples,
		run_tree_algorithms_samples, run_tree_samples, run_trie_tree_samples,
		run_vector_samples };

static void my_finish()
{
	// Call finish method to free runtime allocated memory
	temelia_finish();
}

/*!
 * @usage ./temelia_samples $test_name$
 */
int main(int argc, char **argv)
{
	int i;

	if (argc != 2)
	{
		PRINT("Usage : ./temelia_samples $test_name$\n");
		return EXIT_FAILURE;
	}

	for (i = 0; i < sizeof(test_names) / MAX_TEST_LENGTH; i++)
	{
		if (!strcmp(test_names[i], argv[1]))
		{
			atexit(my_finish);
			PRINT("Running the samples for [%s, %d]\n", test_names[i], i);
			test_pointers[i]();
			return EXIT_SUCCESS;
		}
	}

	return EXIT_FAILURE;
}

void unsigned_int_handler(void *x, FILE *fout)
{
	if ((unsigned long) x == (unsigned long) -1)
		PRINT("-1 ");
	else
	{
		PRINT("%lu ", (unsigned long) x);
	}
}

void double_handler(void *x, FILE *fout)
{
	if (x == NULL)
		PRINT("\n");
	else if (*(double *) x == TEMELIA_INFINITY)
		PRINT("INF ");
	else
		PRINT("%lf ", *(double *) x);
}

void string_handler(void *x, void *context)
{
	PRINT("%s\n", (char *) x);
}

///////////////////////////////////////
// int key specific functions
///////////////////////////////////////

void *int_new(int initial_value)
{
	int *key;

	key = (int *) malloc(sizeof(int));

	if (key)
		*key = initial_value;

	return key;
}

void int_delete(void *key, void *context)
{
	free(key);
}

int int_compare(void *x, void *y, void *context)
{
	if (x == NULL && y == NULL)
		return 0;
	else if (x == NULL && y != NULL)
		return -1;
	else if (x != NULL && y == NULL)
		return 1;
	return *(int *) x - *(int *) y;
}

void int_handler(void *x, void *fout)
{
	if (x == NULL)
		PRINT("\nNULL\n");
	else
		PRINT("%d ", *(int *) x);
}

void int_level_handler(void *key, int level, void *fout)
{
	int i;

	for (i = 0; i < level; i++)
		PRINT(" ");

	if (key == NULL)
		PRINT("\nNULL\n");
	else
		PRINT("%d\n", *(int *) key);
}

int **int_array_new(int size, int max)
{
	int **x, i;

	x = (int **) malloc(size * sizeof(int *));

	for (i = 0; i < size; i++)
	{
		x[i] = (int *) malloc(sizeof(int));
		x[i][0] = rand() % max + 1;
	}

	return x;
}

void int_array_delete(int **data, int size)
{
	int i;

	for (i = 0; i < size; i++)
		free(data[i]);
	free(data);
}

///////////////////////////////////////
// array specific functions
///////////////////////////////////////

void *my_key_at(void *data, int index)
{
	// Basically it's data[index].
	return (void *) ((int **) data)[index];
}

void my_set_key_at(void *data, int index, void *key)
{
	((void **) data)[index] = key;
}

char *my_strdup(char *str)
{
	char *dup;
	int i = 0;

	dup = malloc(128 * sizeof(char));

	while (*str && i < 128)
	{
		dup[i++] = *str;
		str++;
	}
	dup[i] = '\0';

	return dup;
}
